package com.sh.business.service.facade;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import com.sh.business.domain.User;
import com.sh.business.domain.UserFundDetail;
import com.sh.business.domain.UserInvest;
import com.sh.business.domain.form.AirdropManualBo;
import com.sh.business.mapper.UserFundDetailMapper;
import com.sh.business.mapper.UserMapper;
import com.sh.common.core.enums.TransferDescEnum;
import com.sh.common.core.enums.TransferFlagEnum;
import com.sh.common.core.enums.UserFoundEnum;
import com.sh.common.core.exception.ServiceException;
import com.sh.common.core.utils.DateUtils;
import com.sh.common.core.utils.SpringUtils;
import com.sh.common.json.utils.JsonUtils;
import com.sh.system.service.ISysConfigService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;

import static com.sh.common.core.constant.BusinessConstants.*;

@Slf4j
@RequiredArgsConstructor
@Service
public class UserFoundServiceFacade {

    private final UserMapper userMapper;
    private final UserFundDetailMapper userFundDetailMapper;
    private final ISysConfigService iSysConfigService;

    @Transactional
    public void modifyUserFound(Long userId, String orderSn, String txHash, UserFoundEnum userFoundEnum, TransferFlagEnum transferFlagEnum, BigDecimal amount, String transferDesc, String remark) {
        if (userId == 0L || amount.compareTo(BigDecimal.ZERO) <= 0) {
            log.error("更新用户:{},资产金额错误:{}", userId, amount);
            return;
        }

        User user = userMapper.queryByUserIdLock(userId);
        User updateUser = new User();
        updateUser.setUserId(userId);

        // 明细
        UserFundDetail userFundDetail = new UserFundDetail();

        userFundDetail.setUserId(userId);
        userFundDetail.setType(userFoundEnum.getCode());
        userFundDetail.setAmount(amount);
        userFundDetail.setTransferFlag(transferFlagEnum.getCode());
        userFundDetail.setOrderNo(orderSn);
        userFundDetail.setTxHash(txHash);
        userFundDetail.setDescribes(transferDesc);
        userFundDetail.setTxTime(DateUtils.getNowDate());
        userFundDetail.setRemark(remark);

        switch (userFoundEnum) {
            case PURCHASE_COMPUTILITY -> {
                userFundDetail.setPointBefore(user.getPurchaseComputility());
                if (TransferFlagEnum.TRANSFER_IN.getCode().equals(transferFlagEnum.getCode())) {
                    updateUser.setPurchaseComputility(NumberUtil.add(user.getPurchaseComputility(), amount));
                } else {
                    updateUser.setPurchaseComputility(NumberUtil.sub(user.getPurchaseComputility(), amount));
                }
                userFundDetail.setPointAfter(updateUser.getPurchaseComputility());
            }
            case COMPUTILITY -> {
                userFundDetail.setPointBefore(user.getComputility());
                if (TransferFlagEnum.TRANSFER_IN.getCode().equals(transferFlagEnum.getCode())) {
                    updateUser.setComputility(NumberUtil.add(user.getComputility(), amount));
                } else {
                    updateUser.setComputility(NumberUtil.sub(user.getComputility(), amount));
                }
                userFundDetail.setPointAfter(updateUser.getComputility());
            }
            case USDT -> {
                userFundDetail.setPointBefore(user.getUsdt());
                if (TransferFlagEnum.TRANSFER_IN.getCode().equals(transferFlagEnum.getCode())) {
                    updateUser.setUsdt(NumberUtil.add(user.getUsdt(), amount));
                } else {
                    updateUser.setUsdt(NumberUtil.sub(user.getUsdt(), amount));
                }
                userFundDetail.setPointAfter(updateUser.getUsdt());
            }
            case REPURCHASE_USDT -> {
                userFundDetail.setPointBefore(user.getRepurchaseUsdt());
                if (TransferFlagEnum.TRANSFER_IN.getCode().equals(transferFlagEnum.getCode())) {
                    updateUser.setRepurchaseUsdt(NumberUtil.add(user.getRepurchaseUsdt(), amount));
                } else {
                    updateUser.setRepurchaseUsdt(NumberUtil.sub(user.getRepurchaseUsdt(), amount));
                }
                userFundDetail.setPointAfter(updateUser.getRepurchaseUsdt());
            }
            case ALEO -> {
                userFundDetail.setPointBefore(user.getAleo());
                if (TransferFlagEnum.TRANSFER_IN.getCode().equals(transferFlagEnum.getCode())) {
                    updateUser.setAleo(NumberUtil.add(user.getAleo(), amount));
                } else {
                    updateUser.setAleo(NumberUtil.sub(user.getAleo(), amount));
                }
                userFundDetail.setPointAfter(updateUser.getAleo());
            }
            case SCR -> {
                userFundDetail.setPointBefore(user.getScr());
                if (TransferFlagEnum.TRANSFER_IN.getCode().equals(transferFlagEnum.getCode())) {
                    updateUser.setScr(NumberUtil.add(user.getScr(), amount));
                } else {
                    updateUser.setScr(NumberUtil.sub(user.getScr(), amount));
                }
                userFundDetail.setPointAfter(updateUser.getScr());
            }
            case AVAILABLE_SZPN -> {
                userFundDetail.setPointBefore(user.getAvailableSzpn());
                if (TransferFlagEnum.TRANSFER_IN.getCode().equals(transferFlagEnum.getCode())) {
                    updateUser.setAvailableSzpn(NumberUtil.add(user.getAvailableSzpn(), amount));
                } else {
                    updateUser.setAvailableSzpn(NumberUtil.sub(user.getAvailableSzpn(), amount));
                }
                userFundDetail.setPointAfter(updateUser.getAvailableSzpn());
            }
            case FREEZE_SZPN -> {
                userFundDetail.setPointBefore(user.getFreezeSzpn());
                if (TransferFlagEnum.TRANSFER_IN.getCode().equals(transferFlagEnum.getCode())) {
                    updateUser.setFreezeSzpn(NumberUtil.add(user.getFreezeSzpn(), amount));
                } else {
                    updateUser.setFreezeSzpn(NumberUtil.sub(user.getFreezeSzpn(), amount));
                }
                userFundDetail.setPointAfter(updateUser.getFreezeSzpn());
            }
            case FINANCING_SZPN -> {
                userFundDetail.setPointBefore(user.getFinancingSzpn());
                if (TransferFlagEnum.TRANSFER_IN.getCode().equals(transferFlagEnum.getCode())) {
                    updateUser.setFinancingSzpn(NumberUtil.add(user.getFinancingSzpn(), amount));
                } else {
                    updateUser.setFinancingSzpn(NumberUtil.sub(user.getFinancingSzpn(), amount));
                }
                userFundDetail.setPointAfter(updateUser.getFinancingSzpn());
            }
            case TRANSFER_SZPN -> {
                userFundDetail.setPointBefore(user.getTransferSzpn());
                if (TransferFlagEnum.TRANSFER_IN.getCode().equals(transferFlagEnum.getCode())) {
                    updateUser.setTransferSzpn(NumberUtil.add(user.getTransferSzpn(), amount));
                } else {
                    updateUser.setTransferSzpn(NumberUtil.sub(user.getTransferSzpn(), amount));
                }
                userFundDetail.setPointAfter(updateUser.getTransferSzpn());
            }

        }

        // 更新资产
        userMapper.updateById(updateUser);

        // 更新明细
        userFundDetailMapper.insert(userFundDetail);
    }

    @Transactional
    public void changeUserFound(Long userId, UserFoundEnum userFoundEnum, TransferFlagEnum transferFlagEnum, BigDecimal amount) {
        if (userId == 0L || amount.compareTo(BigDecimal.ZERO) <= 0) {
            log.error("更新用户:{},资产金额错误:{}", userId, amount);
            return;
        }

        User user = userMapper.queryByUserIdLock(userId);
        User updateUser = new User();
        updateUser.setUserId(userId);


        switch (userFoundEnum) {
            case PURCHASE_COMPUTILITY -> {
                if (TransferFlagEnum.TRANSFER_IN.getCode().equals(transferFlagEnum.getCode())) {
                    updateUser.setPurchaseComputility(NumberUtil.add(user.getPurchaseComputility(), amount));
                } else {
                    updateUser.setPurchaseComputility(NumberUtil.sub(user.getPurchaseComputility(), amount));
                }
            }
            case COMPUTILITY -> {
                if (TransferFlagEnum.TRANSFER_IN.getCode().equals(transferFlagEnum.getCode())) {
                    updateUser.setComputility(NumberUtil.add(user.getComputility(), amount));
                } else {
                    updateUser.setComputility(NumberUtil.sub(user.getComputility(), amount));
                }
            }
            case USDT -> {
                if (TransferFlagEnum.TRANSFER_IN.getCode().equals(transferFlagEnum.getCode())) {
                    updateUser.setUsdt(NumberUtil.add(user.getUsdt(), amount));
                } else {
                    updateUser.setUsdt(NumberUtil.sub(user.getUsdt(), amount));
                }
            }
            case ALEO -> {
                if (TransferFlagEnum.TRANSFER_IN.getCode().equals(transferFlagEnum.getCode())) {
                    updateUser.setAleo(NumberUtil.add(user.getAleo(), amount));
                } else {
                    updateUser.setAleo(NumberUtil.sub(user.getAleo(), amount));
                }
            }
            case SCR -> {
                if (TransferFlagEnum.TRANSFER_IN.getCode().equals(transferFlagEnum.getCode())) {
                    updateUser.setScr(NumberUtil.add(user.getScr(), amount));
                } else {
                    updateUser.setScr(NumberUtil.sub(user.getScr(), amount));
                }
            }
            case SELF_ACHIEVEMENT -> {
                if (TransferFlagEnum.TRANSFER_IN.getCode().equals(transferFlagEnum.getCode())) {
                    updateUser.setSelfAchievement(NumberUtil.add(user.getSelfAchievement(), amount));
                } else {
                    updateUser.setSelfAchievement(NumberUtil.sub(user.getSelfAchievement(), amount));
                }
            }
            case DIRECT_PUSH_ACHIEVEMENT -> {
                if (TransferFlagEnum.TRANSFER_IN.getCode().equals(transferFlagEnum.getCode())) {
                    updateUser.setDirectPushAchievement(NumberUtil.add(user.getDirectPushAchievement(), amount));
                } else {
                    updateUser.setDirectPushAchievement(NumberUtil.sub(user.getDirectPushAchievement(), amount));
                }
            }
            case TEAM_ACHIEVEMENT -> {
                if (TransferFlagEnum.TRANSFER_IN.getCode().equals(transferFlagEnum.getCode())) {
                    updateUser.setTeamAchievement(NumberUtil.add(user.getTeamAchievement(), amount));
                } else {
                    updateUser.setTeamAchievement(NumberUtil.sub(user.getTeamAchievement(), amount));
                }
            }

        }

        // 更新资产
        userMapper.updateById(updateUser);

    }

    /**
     * 获得空投及算力
     */
    public void airdropAndComputility(UserInvest userInvest) {
        // szpn价格
        BigDecimal szpnPrice = Convert.toBigDecimal(iSysConfigService.selectConfigByKey("biz.szpn.price"));

        // 1、获得空投(锁仓szpn)
        User user = userMapper.selectById(userInvest.getUserId());
        BigDecimal airdropRatio = user.getIsNode() ? BigDecimal.ONE : Convert.toBigDecimal(iSysConfigService.selectConfigByKey("biz.airdrop.ratio"));

        BigDecimal szpnAmount = NumberUtil.div(userInvest.getAmount(), szpnPrice).setScale(6, RoundingMode.DOWN);
        BigDecimal airdropAmount = NumberUtil.mul(szpnAmount, airdropRatio);

        // 空投账户 扣除szpn
        SpringUtils.getAopProxy(this).modifyUserFound(AIRDROP_ID,
            userInvest.getOrderSn(),
            userInvest.getTxHash(),
            UserFoundEnum.FREEZE_SZPN,
            TransferFlagEnum.TRANSFER_OUT,
            airdropAmount,
            TransferDescEnum.AIRDROP.getCode().toString(),
            null);

        // 用户账户 增加szpn
        SpringUtils.getAopProxy(this).modifyUserFound(user.getUserId(),
                userInvest.getOrderSn(),
                userInvest.getTxHash(),
                UserFoundEnum.FREEZE_SZPN,
                TransferFlagEnum.TRANSFER_IN,
                airdropAmount,
                TransferDescEnum.AIRDROP.getCode().toString(),
                null);

        // 2、获得算力
        BigDecimal purchaseComputility = NumberUtil.mul(userInvest.getAmount(), BigDecimal.TEN);
        SpringUtils.getAopProxy(this).modifyUserFound(user.getUserId(),
                userInvest.getOrderSn(),
                userInvest.getTxHash(),
                UserFoundEnum.COMPUTILITY,
                TransferFlagEnum.TRANSFER_IN,
                purchaseComputility,
                TransferDescEnum.PURCHASE_MINING.getCode().toString(),
                null);

        SpringUtils.getAopProxy(this).changeUserFound(user.getUserId(),
                UserFoundEnum.PURCHASE_COMPUTILITY,
                TransferFlagEnum.TRANSFER_IN,
                purchaseComputility
        );
    }

    /**
     * 获得空投及算力
     */
    public boolean airdropManual(AirdropManualBo airdropManualBo) {


        // 空投账户 扣除szpn
        SpringUtils.getAopProxy(this).modifyUserFound(AIRDROP_ID,
                null,
                null,
                UserFoundEnum.FREEZE_SZPN,
                TransferFlagEnum.TRANSFER_OUT,
                airdropManualBo.getAmount(),
                TransferDescEnum.AIRDROP.getCode().toString(),
                "人工空投");

        // 用户账户 增加szpn
        SpringUtils.getAopProxy(this).modifyUserFound(airdropManualBo.getUserId(),
                null,
                null,
                UserFoundEnum.FREEZE_SZPN,
                TransferFlagEnum.TRANSFER_IN,
                airdropManualBo.getAmount(),
                TransferDescEnum.AIRDROP.getCode().toString(),
                "人工空投");

        // 2、获得算力 todo:20250309 人工空投不给算力
        /*BigDecimal purchaseComputility = NumberUtil.mul(airdropManualBo.getAmount(), BigDecimal.TEN);
        SpringUtils.getAopProxy(this).modifyUserFound(airdropManualBo.getUserId(),
                null,
                null,
                UserFoundEnum.COMPUTILITY,
                TransferFlagEnum.TRANSFER_IN,
                purchaseComputility,
                TransferDescEnum.PURCHASE_MINING.getCode().toString(),
                "人工空投");

        SpringUtils.getAopProxy(this).changeUserFound(airdropManualBo.getUserId(),
                UserFoundEnum.PURCHASE_COMPUTILITY,
                TransferFlagEnum.TRANSFER_IN,
                purchaseComputility
        );*/

        return true;
    }

    /**
     * 社区扶持
     */
    public boolean communitySupport(AirdropManualBo airdropManualBo) {


        // 社区扶持账户 扣除szpn
        SpringUtils.getAopProxy(this).modifyUserFound(BENEFIT_ID,
                null,
                null,
                UserFoundEnum.TRANSFER_SZPN,
                TransferFlagEnum.TRANSFER_OUT,
                airdropManualBo.getAmount(),
                TransferDescEnum.COMMUNITY_SUPPORT.getCode().toString(),
                "社区扶持");

        // 用户账户 增加szpn
        SpringUtils.getAopProxy(this).modifyUserFound(airdropManualBo.getUserId(),
                null,
                null,
                UserFoundEnum.TRANSFER_SZPN,
                TransferFlagEnum.TRANSFER_IN,
                airdropManualBo.getAmount(),
                TransferDescEnum.COMMUNITY_SUPPORT.getCode().toString(),
                "社区扶持");


        return true;
    }

    /**
     * 社区扶持
     */
    public boolean modifyAsset(AirdropManualBo airdropManualBo) {

        Long fromUserId = COMPANY_ID;

        switch (UserFoundEnum.of(airdropManualBo.getAssetType())) {
            case TRANSFER_SZPN:
                fromUserId = BENEFIT_ID;
                break;
            case FREEZE_SZPN:
                fromUserId = AIRDROP_ID;
                break;
            default:
                fromUserId = COMPANY_ID;
        }

        // 公司
        if (ObjectUtil.notEqual(UserFoundEnum.COMPUTILITY.getCode(), airdropManualBo.getAssetType())) {
            SpringUtils.getAopProxy(this).modifyUserFound(fromUserId,
                null,
                null,
                UserFoundEnum.of(airdropManualBo.getAssetType()),
                TransferFlagEnum.of(airdropManualBo.getTransferFlag() * -1),
                airdropManualBo.getAmount(),
                TransferDescEnum.COMMUNITY_SUPPORT.getCode().toString(),
                "后台操作");
        }

        // 用户账户
        SpringUtils.getAopProxy(this).modifyUserFound(airdropManualBo.getUserId(),
            null,
            null,
            UserFoundEnum.of(airdropManualBo.getAssetType()),
            TransferFlagEnum.of(airdropManualBo.getTransferFlag()),
            airdropManualBo.getAmount(),
            TransferDescEnum.COMMUNITY_SUPPORT.getCode().toString(),
            "后台操作");

        // 算力
        /*if (ObjectUtil.equal(UserFoundEnum.COMPUTILITY.getCode(), airdropManualBo.getAssetType()) && ObjectUtil.equal(airdropManualBo.getTransferFlag(), TransferFlagEnum.TRANSFER_OUT.getCode())) {
            // 购买算力
            SpringUtils.getAopProxy(this).changeUserFound(airdropManualBo.getUserId(),
                UserFoundEnum.PURCHASE_COMPUTILITY,
                TransferFlagEnum.of(airdropManualBo.getTransferFlag()),
                airdropManualBo.getAmount()
            );

        }*/


        return true;
    }


}
